package attribute;

import be.kuleuven.cs.som.annotate.*;

/**
 * ...
 * 		|isValidEnergyUnit(energy.getEnergyUnit)
 *
 */
/**
 * @author John Breyssem	1Ba Informatica		r0303394
 * 
 * @author Lars Feyaerts	1Ba Informatica		r0296831
 * 
 * @version	1.3
 *
 */
@Value
public class Energy implements Comparable<Energy>{
	
	private final Double energy;
	private final EnergyUnit energyUnit;
	
	public Energy(double energy, EnergyUnit unit){
		this.energy = energy;
		this.energyUnit = unit;
	}
	
	/**
	 * Returns the energy double of this energy.
	 */
	@Basic @Immutable
	public double getEnergyDouble(){
		return this.energy;
	}
	
	/**
	 * Returns the energy unit of this energy.
	 */
	@Basic @Immutable
	public EnergyUnit getEnergyUnit(){
		return this.energyUnit;
	}	
	
	/**
	 * Check whether the given energyUnit is a valid unit for any energy.
	 * 
	 * @param unit
	 * 			...
	 * @return ...
	 * 			|result == (unit!= null)
	 */
	public static boolean isValidEnergyUnit(EnergyUnit unit){
		return unit != null;
	}
	
	/**
	 * Compute the sum of this energy and the other energy.
	 * 
	 * @param other
	 * 			The other energy to add.
	 * @pre	...
	 * 			|other != null
	 * @return ...
	 * 			|result.getEnergyUnit() == this.getEnergyUnit()
	 * @return ...
	 * 			|if(this.getEnergyUnit() == other.getEnergyUnit())
	 * 			|	then result.getEnergyDouble().equals
	 * 			|		this.getEnergyDouble() + other.getEnergyDouble()
	 * @return ...		
	 * 			|if(this.getEnergyUnit() != other.getEnergyUnit()
	 * 			|	then result.equals
	 * 			|	 this.add(other.toEnergy(this.getEnergyUnit())
	 */
	public Energy add(Energy other){
		assert(other != null);
		if(this.getEnergyUnit() == other.getEnergyUnit())
			return new Energy(this.getEnergyDouble() + other.getEnergyDouble(), this.getEnergyUnit());
		return this.add(other.toEnergy(this.getEnergyUnit()));
	}
	
	/**
	 * Compute the subtraction of the other energy from this energy.
	 * 
	 * @param other
	 * 			The energy to be subtract.
	 * @pre ...
	 * 			|other != null
	 * @return ...
	 * 			|result.getEnergyUnit() == this.getEnergyUnit()
	 * @return ...	
	 * 			|if(this.getEnergyUnit() == other.getEnergyUnit())
	 * 			|	then result.getEnergyDouble().equals
	 * 			|		this.getEnergyDouble() - other.getEnergyDouble())
	 * @return ...
	 * 			|if(this.getEnergyUnit() != other.getEnergyUnit()
	 * 			|	then result.equals
	 * 			|	 this.subtract(other.toEnergy(this.getEnergyUnit())
	 * 
	 */
	public Energy subtract(Energy other){
		assert(other != null);
		if(this.getEnergyUnit() == other.getEnergyUnit())
			return new Energy(this.getEnergyDouble() - other.getEnergyDouble(), this.getEnergyUnit());
		return this.subtract(other.toEnergy(this.getEnergyUnit()));
	}
	
	/**
	 * Return an energy that has the same value as this energy expressed in the given energy unit
	 * 
	 * @param energy
	 * 			The energy to be converted.
	 * @pre ...
	 * 			|energyUnit != null
	 * @return ...
	 * 			|result.getEnergyUnit() == energyUnit
	 * @return ...
	 * 			|let
	 * 			|	exchangeRate = this.getEnergyUnit().toEnergy(energyUnit),
	 * 			|	doubleOfEnergyUnit = this.getEnergyDouble() * exchangeRate
	 * 			|in
	 * 			|	result.getEnergyDouble().equals
	 * 			|	  (doubleOfEnergyUnit)
	 * 			
	 */
	public Energy toEnergy(EnergyUnit energyUnit){
		assert(energyUnit != null);
		if(this.getEnergyUnit() == energyUnit)
			return this;
		Double exchangeRate = this.getEnergyUnit().toEnergy(energyUnit);
		Double doubleOfEnergyUnit = this.getEnergyDouble() * exchangeRate;
		return new Energy(doubleOfEnergyUnit, energyUnit);
	}

	/**
	 * 
	 * @param other
	 * 
	 * @return ...
	 * 			|if(this.getEnergynit() == other.getEnergyUnit()
	 * 			|	then new Double(result.getEnergyDouble()).compareTo(other.getEnergyDouble())
	 * @return ...
	 * 			|if(this.getEnergyUnit() != other.getEnergyUnit()
	 * 			|	then this.compareTo(other.toEnergy(this.getEnergyUnit))
	 * @pre ...	
	 *		|other != null
	 */
	@Override
	public int compareTo(Energy other) {
		assert((other != null) );
		if(this.getEnergyUnit() == other.getEnergyUnit())
			return new Double(this.getEnergyDouble()).compareTo(other.getEnergyDouble());
		return this.compareTo(other.toEnergy(this.getEnergyUnit()));
	}
	
	/**
	 * Multiplies this energyDouble with the given number.
	 * 
	 * @param number
	 * 			The number to be multiplied.
	 * @return ...
	 * 			|result.getEnergyDouble().equals
	 * 			|		this.getEnergyDouble() * number)
	 */
	public Energy times(int number){
		return new Energy(this.getEnergyDouble()*number, this.getEnergyUnit());
	}
	
	/**
	 * Divides this energyDouble with the given number.
	 * 
	 * @param number	
	 * 			The number to be divided.
	 * @return ...
	 * 			|result.getEnergyDouble().equals
	 * 			|	this.getEnergyDouble() / number
	 */
	public Energy divide(int number){
		return new Energy(this.getEnergyDouble()/number, this.getEnergyUnit());
	}
}
